From be4264409148b58236b2510d7050cd96e6f1b141 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 26 Apr 2021 17:02:50 -0400 Subject: [PATCH] Add more clipboard tests This tests the simple cases of copying text, files, colors or images between processes. --- testsuite/gdk/clipboard-client.c | 364 +++++++++++++++++++++++++++++++ testsuite/gdk/clipboard.c | 199 +++++++++++++++++ testsuite/gdk/meson.build | 7 + 3 files changed, 570 insertions(+) create mode 100644 testsuite/gdk/clipboard-client.c diff --git a/testsuite/gdk/clipboard-client.c b/testsuite/gdk/clipboard-client.c new file mode 100644 index 0000000000..346bac2d7c --- /dev/null +++ b/testsuite/gdk/clipboard-client.c @@ -0,0 +1,364 @@ +#include + +#ifdef GDK_WINDOWING_WAYLAND +#include "wayland/gdkwayland.h" +#endif + +static void +got_string_cb (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GdkClipboard *clipboard = GDK_CLIPBOARD (source); + GError *error = NULL; + char *text; + + text = gdk_clipboard_read_text_finish (clipboard, result, &error); + if (text) + { + g_print ("%s", text); + g_free (text); + } + else + { + g_print ("ERROR: %s", error->message); + g_clear_error (&error); + } + + exit (0); +} + +static void +got_text_cb (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GdkClipboard *clipboard = GDK_CLIPBOARD (source); + GError *error = NULL; + char *text; + + text = gdk_clipboard_read_text_finish (clipboard, result, &error); + if (text) + { + int fd; + char *name; + + fd = g_file_open_tmp ("XXXXXX.out", &name, &error); + if (error) + g_error ("Failed to create tmp file: %s", error->message); + close (fd); + g_file_set_contents (name, text, -1, &error); + g_print ("%s", name); + g_free (text); + g_free (name); + } + else + { + g_print ("ERROR: %s", error->message); + g_clear_error (&error); + } + + exit (0); +} + +static void +got_texture_cb (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GdkClipboard *clipboard = GDK_CLIPBOARD (source); + GError *error = NULL; + GdkTexture *texture; + + texture = gdk_clipboard_read_texture_finish (clipboard, result, &error); + if (texture) + { + int fd; + char *name; + + fd = g_file_open_tmp ("XXXXXX.out", &name, &error); + if (error) + g_error ("Failed to create tmp file: %s", error->message); + close (fd); + gdk_texture_save_to_png (texture, name); + g_print ("%s", name); + g_object_unref (texture); + g_free (name); + } + else + { + g_print ("ERROR: %s", error->message); + g_clear_error (&error); + } + + exit (0); +} + +static void +got_file (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GdkClipboard *clipboard = GDK_CLIPBOARD (source); + GError *error = NULL; + const GValue *value; + + value = gdk_clipboard_read_value_finish (clipboard, result, &error); + if (value) + { + GFile *file = g_value_get_object (value); + char *path = g_file_get_path (file); + g_print ("%s", path); + g_free (path); + } + else + { + g_print ("ERROR: %s", error->message); + g_clear_error (&error); + } + + exit (0); +} + +static void +got_files (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GdkClipboard *clipboard = GDK_CLIPBOARD (source); + GError *error = NULL; + const GValue *value; + + value = gdk_clipboard_read_value_finish (clipboard, result, &error); + if (value) + { + GSList *files = g_value_get_boxed (value); + for (GSList *l = files; l; l = l->next) + { + GFile *file = l->data; + char *path = g_file_get_path (file); + if (l != files) + g_print (":"); + g_print ("%s", path); + g_free (path); + } + } + else + { + g_print ("ERROR: %s", error->message); + g_clear_error (&error); + } + + exit (0); +} + +static void +got_color (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GdkClipboard *clipboard = GDK_CLIPBOARD (source); + GError *error = NULL; + const GValue *value; + + value = gdk_clipboard_read_value_finish (clipboard, result, &error); + if (value) + { + GdkRGBA *color = g_value_get_boxed (value); + char *s = gdk_rgba_to_string (color); + g_print ("%s", s); + g_free (s); + } + else + { + g_print ("ERROR: %s", error->message); + g_clear_error (&error); + } + + exit (0); +} + +static const char *action; +static const char *type; +static const char *value; +static gulong handler; + +static void +do_it (GObject *object, + GParamSpec *pspec) +{ + GdkClipboard *clipboard; + + g_signal_handler_disconnect (object, handler); + + clipboard = gdk_display_get_clipboard (gdk_display_get_default ()); + + if (strcmp (action, "info") == 0) + { + GdkContentFormats *formats; + char *s; + + formats = gdk_clipboard_get_formats (clipboard); + s = gdk_content_formats_to_string (formats); + g_print ("%s\n", s); + g_free (s); + } + else if (strcmp (action, "set") == 0) + { + GdkContentFormats *formats; + char *s; + + if (strcmp (type, "string") == 0) + { + gdk_clipboard_set_text (clipboard, value); + } + else if (strcmp (type, "text") == 0) + { + char *contents; + gsize len; + + if (!g_file_get_contents (value, &contents, &len, NULL)) + g_error ("Failed to read %s\n", value); + + gdk_clipboard_set_text (clipboard, contents); + g_free (contents); + } + else if (strcmp (type, "image") == 0) + { + GFile *file; + GdkTexture *texture; + + file = g_file_new_for_commandline_arg (value); + texture = gdk_texture_new_from_file (file, NULL); + if (!texture) + g_error ("Failed to read %s\n", value); + + gdk_clipboard_set_texture (clipboard, texture); + g_object_unref (texture); + g_object_unref (file); + } + else if (strcmp (type, "file") == 0) + { + GFile *file; + + file = g_file_new_for_commandline_arg (value); + gdk_clipboard_set (clipboard, G_TYPE_FILE, file); + g_object_unref (file); + } + else if (strcmp (type, "files") == 0) + { + char **strv; + GSList *files; + + strv = g_strsplit (value, ":", 0); + + files = NULL; + for (int i = 0; strv[i]; i++) + files = g_slist_append (files, g_file_new_for_commandline_arg (strv[i])); + + gdk_clipboard_set (clipboard, GDK_TYPE_FILE_LIST, files); + + g_slist_free_full (files, g_object_unref); + g_strfreev (strv); + } + else if (strcmp (type, "color") == 0) + { + GdkRGBA color; + + gdk_rgba_parse (&color, value); + gdk_clipboard_set (clipboard, GDK_TYPE_RGBA, &color); + } + else + g_error ("can't set %s", type); + + formats = gdk_clipboard_get_formats (clipboard); + s = gdk_content_formats_to_string (formats); + g_print ("%s\n", s); + g_free (s); + } + else if (strcmp (action, "get") == 0) + { + if (strcmp (type, "string") == 0) + { + gdk_clipboard_read_text_async (clipboard, NULL, got_string_cb, NULL); + } + else if (strcmp (type, "text") == 0) + { + gdk_clipboard_read_text_async (clipboard, NULL, got_text_cb, NULL); + } + else if (strcmp (type, "image") == 0) + { + gdk_clipboard_read_texture_async (clipboard, NULL, got_texture_cb, NULL); + } + else if (strcmp (type, "file") == 0) + { + gdk_clipboard_read_value_async (clipboard, G_TYPE_FILE, 0, NULL, got_file, NULL); + } + else if (strcmp (type, "files") == 0) + { + gdk_clipboard_read_value_async (clipboard, GDK_TYPE_FILE_LIST, 0, NULL, got_files, NULL); + } + else if (strcmp (type, "color") == 0) + { + gdk_clipboard_read_value_async (clipboard, GDK_TYPE_RGBA, 0, NULL, got_color, NULL); + } + else + g_error ("can't get %s", type); + } + else + g_error ("can only set, get or info"); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + gboolean done = FALSE; + + if (argc < 2) + g_error ("too few arguments"); + + action = argv[1]; + + if (strcmp (action, "info") == 0) + { + } + else if (strcmp (action, "set") == 0) + { + if (argc < 4) + g_error ("too few arguments for set"); + + type = argv[2]; + value = argv[3]; + } + else if (strcmp (action, "get") == 0) + { + if (argc < 3) + g_error ("too few arguments for get"); + + type = argv[2]; + } + else + g_error ("can only set or get"); + + gtk_init (); + + /* Don't wait for a window manager to give us focus when + * we may be running on bare wm-less X. + */ +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) + { + window = gtk_window_new (); + gtk_window_present (GTK_WINDOW (window)); + handler = g_signal_connect (window, "notify::is-active", G_CALLBACK (do_it), NULL); + } + else +#endif + do_it (NULL, NULL); + + while (!done) + g_main_context_iteration (NULL, TRUE); + + return 0; +} diff --git a/testsuite/gdk/clipboard.c b/testsuite/gdk/clipboard.c index aa3b1055f2..9569de927b 100644 --- a/testsuite/gdk/clipboard.c +++ b/testsuite/gdk/clipboard.c @@ -70,6 +70,199 @@ test_clipboard_basic (void) g_value_unset (&value); } +static void +read_upto_done (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GDataInputStream *out = G_DATA_INPUT_STREAM (source); + gboolean *done = data; + char *str; + GError *error = NULL; + + str = g_data_input_stream_read_upto_finish (out, result, NULL, &error); + g_assert_no_error (error); + g_free (str); + + *done = TRUE; + g_main_context_wakeup (NULL); +} + +static void +assert_texture_equal (GdkTexture *t1, + GdkTexture *t2) +{ + int width; + int height; + int stride; + guchar *d1; + guchar *d2; + + width = gdk_texture_get_width (t1); + height = gdk_texture_get_height (t1); + stride = 4 * width; + + g_assert_cmpint (width, ==, gdk_texture_get_width (t2)); + g_assert_cmpint (height, ==, gdk_texture_get_height (t2)); + + d1 = g_malloc (stride * height); + d2 = g_malloc (stride * height); + + gdk_texture_download (t1, d1, stride); + gdk_texture_download (t2, d2, stride); + + g_assert_cmpmem (d1, stride * height, d2, stride * height); + + g_free (d1); + g_free (d2); +} + +static void +test_clipboard_roundtrip (const char *type, + const char *value, + const char *result) +{ + GSubprocess *source, *target; + char *clipboard_client; + GError *error = NULL; + GDataInputStream *out; + gboolean done = FALSE; + char *stdout_buf = NULL; + char *stderr_buf = NULL; + + clipboard_client = g_test_build_filename (G_TEST_BUILT, "/clipboard-client", NULL); + + source = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, + &error, + clipboard_client, + "set", type, value, NULL); + g_assert_no_error (error); + + /* Wait until the first child has claimed the clipboard */ + out = g_data_input_stream_new (g_subprocess_get_stdout_pipe (source)); + g_data_input_stream_read_upto_async (out, "\n", 1, 0, NULL, read_upto_done, &done); + + while (!done) + g_main_context_iteration (NULL, TRUE); + + g_object_unref (out); + + target = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, + &error, + clipboard_client, + "get", type, NULL); + + g_free (clipboard_client); + + if (!target) + { + g_test_fail (); + g_error_free (error); + + g_subprocess_force_exit (source); + g_object_unref (source); + + return; + } + + g_subprocess_communicate_utf8 (target, NULL, NULL, &stdout_buf, &stderr_buf, &error); + + g_subprocess_force_exit (source); + g_object_unref (source); + + g_assert_no_error (error); + + if (result) + g_assert_cmpstr (stdout_buf, ==, result); + else if (g_str_has_prefix (stdout_buf, "ERROR")) + { + g_test_fail (); + } + else if (g_str_has_suffix (value, ".png")) + { + GFile *f1, *f2; + GdkTexture *t1, *t2; + + f1 = g_file_new_for_path (value); + f2 = g_file_new_for_path (stdout_buf); + + t1 = gdk_texture_new_from_file (f1, &error); + g_assert_no_error (error); + t2 = gdk_texture_new_from_file (f2, &error); + g_assert_no_error (error); + + assert_texture_equal (t1, t2); + + g_object_unref (t1); + g_object_unref (t2); + g_object_unref (f1); + g_object_unref (f2); + } + else + { + char *m1, *m2; + gsize l1, l2; + + g_file_get_contents (value, &m1, &l1, &error); + g_assert_no_error (error); + g_file_get_contents (stdout_buf, &m2, &l2, &error); + g_assert_no_error (error); + + g_assert_cmpmem (m1, l1, m2, l2); + + g_free (m1); + g_free (m2); + } + + g_assert_null (stderr_buf); + g_free (stdout_buf); + g_object_unref (target); +} + +static void +test_clipboard_string (void) +{ + test_clipboard_roundtrip ("string", "abcdef1230", "abcdef1230"); +} + +static void +test_clipboard_text (void) +{ + char *filename; + + filename = g_test_build_filename (G_TEST_DIST, "../../../gtk/gtkwidget.h", NULL); + + test_clipboard_roundtrip ("text", filename, NULL); +} + +static void +test_clipboard_image (void) +{ + char *filename; + + filename = g_test_build_filename (G_TEST_DIST, "../../../gtk/icons/32x32/places/network-workgroup.png", NULL); + + test_clipboard_roundtrip ("image", filename, NULL); +} + +static void +test_clipboard_color (void) +{ + test_clipboard_roundtrip ("color", "red", "rgb(255,0,0)"); +} + +static void +test_clipboard_file (void) +{ + test_clipboard_roundtrip ("file", "/etc/passwd", "/etc/passwd"); +} + +static void +test_clipboard_files (void) +{ + test_clipboard_roundtrip ("files", "/etc/passwd:/boot/ostree", "/etc/passwd:/boot/ostree"); +} + int main (int argc, char *argv[]) { @@ -78,6 +271,12 @@ main (int argc, char *argv[]) gtk_init (); g_test_add_func ("/clipboard/basic", test_clipboard_basic); + g_test_add_func ("/clipboard/string", test_clipboard_string); + g_test_add_func ("/clipboard/text", test_clipboard_text); + g_test_add_func ("/clipboard/image", test_clipboard_image); + g_test_add_func ("/clipboard/color", test_clipboard_color); + g_test_add_func ("/clipboard/file", test_clipboard_file); + g_test_add_func ("/clipboard/files", test_clipboard_files); return g_test_run (); } diff --git a/testsuite/gdk/meson.build b/testsuite/gdk/meson.build index 5216d7a518..edc290ff7a 100644 --- a/testsuite/gdk/meson.build +++ b/testsuite/gdk/meson.build @@ -1,3 +1,10 @@ +clipboard_client = executable('clipboard-client', + sources: ['clipboard-client.c'], + include_directories: [confinc], + c_args: common_cflags, + dependencies: [ libgtk_dep ], + install: false) + testexecdir = join_paths(installed_test_bindir, 'gdk') testdatadir = join_paths(installed_test_datadir, 'gdk') -- 2.30.2